#include<iostream>
#include<unistd.h>
#include<string>
#include<vector>
#include<sys/wait.h>
#include<sys/types.h>
#include"Test.hpp"

using namespace std;

//master
class Channel
{
public:
    Channel(int wfd,pid_t id,const string& name)
        :_wfd(wfd)
        ,_subprocessid(id)
        ,_name(name)
    {}
    int GetWfd(){return _wfd;}
    pid_t GetProcessId(){return _subprocessid;}
    string GetName(){return _name;}
    void CloseChannel(){close(_wfd);}
    void Wait()
    {
        pid_t rid=waitpid(_subprocessid,nullptr,0);
        if(rid>0)
        {
            cout<<"wait "<<rid<<" success "<<endl;
        }
    }
    ~Channel()
    {}
private:
    int _wfd;
    pid_t _subprocessid;
    string _name;
};
//形参类型命名规范
//const &：输出
//& 输入输出
//* 输出型参数
void CreateChannelAndSub(vector<Channel>*Channels ,int num,task_t task)
{
    for(int i=0;i<num;i++)
    {
        //1.创建管道
        int pipefd[2]={0};
        int n=pipe(pipefd);
        if(n<0) exit(1);

        //2.创建子进程

        pid_t id=fork();
        if(id==0)
        {
            if(!Channels->empty())
            {
                //第二次之后创建新的管道
                for(auto &Channel:*Channels)
                {
                    Channel.CloseChannel();
                }
            }
            //child - read
            close(pipefd[1]);
            //work(pipefd[0]);
            dup2(pipefd[0],0);
            task();
            close(pipefd[0]);
            exit(0);
        }

        //3.构建一个channel名称
        string channel_name="Channel-"+to_string(i);

        //father - write
        close(pipefd[0]);
        //子进程的pid
        //父进程关心的管道write
        Channels->push_back(Channel(pipefd[1],id,channel_name));

    }
}

int NextChannel(int channelnum)
{
    static int next=0;
    int channel=next;
    next++;
    next%=channelnum;
    return channel;
}

void SendTaskCommand(Channel& Channel,int taskcommand)
{
    write(Channel.GetWfd(),&taskcommand,sizeof(taskcommand));
}
void ctrlProcessOnce(vector<Channel>& Channels)
{
    sleep(1);
    //a.选择一个任务
    int taskcommand=SelectTask();
    //b.选择一个信道和进程
    int channel_index=NextChannel(Channels.size());
    //c.发送任务
    SendTaskCommand(Channels[channel_index],taskcommand);
    cout<<"taskcommand: "<<taskcommand<<"channel: "\
    <<Channels[channel_index].GetName()<<"sub process: "\
    <<Channels[channel_index].GetProcessId()<<endl;
    
}

void ctrlProcess(vector<Channel>& Channels,int times=-1)
{
    if(times>0)
    {
        while(times--)
        {
            ctrlProcessOnce(Channels);
        }
    }
    else{
        while(true)
        {
            ctrlProcessOnce(Channels);    
        }
    }

}
void CleanUpChannels(vector<Channel>& Channels)
{
    for(auto &Channel:Channels)
    {
        Channel.CloseChannel();
        Channel.Wait();
    }
    // for(auto &Channel:Channels)
    // {
    //     Channel.CloseChannel();
    // }
    // for(auto &Channel:Channels)
    // {
    //     Channel.Wait();
    // }
}

// ./processpool 5
int main(int argc,char *argv[])
{
    if(argc!=2)
    {
        cerr<<"Usage: "<<argv[0]<<" processnum "<<endl;
        return 1;
    }

    int num=stoi(argv[1]);
    LoadTask();

    vector<Channel> Channels;
    //1.创建信道和子进程
    CreateChannelAndSub(&Channels,num,work);
    
    //2.通过channel控制子进程
    ctrlProcess(Channels,10);
    //3.回收管道和子进程
    //a.关闭所有的写端
    //b.回收子进程
    CleanUpChannels(Channels);

    // for(auto&Channel:Channels)
    // {
    //     cout<<"======================"<<endl;
    //     cout<<Channel.GetName()<<endl;
    //     cout<<Channel.GetWfd()<<endl;
    //     cout<<Channel.GetProcessId()<<endl;
    // }
    // sleep(100);

    return 0;
}